import { LcProjectAsset } from '@/types/modules/editor/types/asset.type';
import {
  DocFrameType,
  LcProject,
} from '@/types/modules/editor/types/editor.type';
import {
  IPublicTypeAssetsJson,
  IPublicTypeRemoteComponentDescription,
} from '@alilc/lowcode-types';
import { getDefaultAssets } from './assetsToPackages';
import { getOEMConfig } from '../../../modules/oem/oemConfig';

export const filterAssets = (
  assets: LcProject['assets'],
  frame?: DocFrameType,
) => {
  return assets
    ?.filter((_) => {
      if (!_?.package) return false;
      const enable =
        _.enable !== false &&
        (!_.advanced?.frames ||
          _.advanced?.frames.length === 0 ||
          _.advanced?.frames?.includes(frame));
      return enable;
    })
    ?.map((_) => JSON.parse(JSON.stringify(_)));
};

const buildLceAssetFromDsAsset = (asset: LcProjectAsset) => {
  const component = {
    exportName: asset.metaFile?.exportName,
    npm: {
      package: asset.package.package,
      version: asset.package.version,
    },
    url: asset.metaFile?.url,
  } as IPublicTypeRemoteComponentDescription;
};

/**
 * 转换资产URL以适配OEM配置
 * @param url 原始URL
 * @param oemConfig OEM配置
 * @returns 转换后的URL
 */
const transformUrlForOEM = (url: string, oemConfig: any): string => {
  if (!url || typeof url !== 'string') return url;

  // 替换默认的CDN域名
  const defaultCdnDomains = ['cdn.appthen.com', 'cdn.appthen.cn'];
  let transformedUrl = url;

  defaultCdnDomains.forEach((domain) => {
    if (transformedUrl.includes(domain)) {
      transformedUrl = transformedUrl.replace(domain, oemConfig.cdnDomain);
    }
  });

  return transformedUrl;
};

/**
 * 转换资产包以适配OEM配置
 * @param asset 资产包
 * @param oemConfig OEM配置
 * @returns 转换后的资产包
 */
const transformAssetForOEM = (asset: any, oemConfig: any): any => {
  if (!asset) return asset;

  const transformedAsset = { ...asset };

  // 转换urls数组
  if (transformedAsset.urls && Array.isArray(transformedAsset.urls)) {
    transformedAsset.urls = transformedAsset.urls.map((url: string) =>
      transformUrlForOEM(url, oemConfig),
    );
  }

  // 转换editUrls数组
  if (transformedAsset.editUrls && Array.isArray(transformedAsset.editUrls)) {
    transformedAsset.editUrls = transformedAsset.editUrls.map((url: string) =>
      transformUrlForOEM(url, oemConfig),
    );
  }

  // 转换单个url
  if (transformedAsset.url) {
    transformedAsset.url = transformUrlForOEM(transformedAsset.url, oemConfig);
  }

  // 转换urls对象中的所有URL（仅在urls不是数组时处理）
  if (
    transformedAsset.urls &&
    typeof transformedAsset.urls === 'object' &&
    !Array.isArray(transformedAsset.urls)
  ) {
    const urlsObj: any = {};
    Object.keys(transformedAsset.urls).forEach((key) => {
      const urls = transformedAsset.urls[key];
      if (Array.isArray(urls)) {
        urlsObj[key] = urls.map((url: string) =>
          transformUrlForOEM(url, oemConfig),
        );
      } else {
        urlsObj[key] = transformUrlForOEM(urls, oemConfig);
      }
    });
    transformedAsset.urls = urlsObj;
  }

  // 转换advancedUrls对象中的所有URL
  if (transformedAsset.advancedUrls) {
    const advancedUrls: any = {};
    Object.keys(transformedAsset.advancedUrls).forEach((key) => {
      const urls = transformedAsset.advancedUrls[key];
      if (Array.isArray(urls)) {
        advancedUrls[key] = urls.map((url: string) =>
          transformUrlForOEM(url, oemConfig),
        );
      } else {
        advancedUrls[key] = transformUrlForOEM(urls, oemConfig);
      }
    });
    transformedAsset.advancedUrls = advancedUrls;
  }

  // 转换advancedEditUrls对象中的所有URL
  if (transformedAsset.advancedEditUrls) {
    const advancedEditUrls: any = {};
    Object.keys(transformedAsset.advancedEditUrls).forEach((key) => {
      const urls = transformedAsset.advancedEditUrls[key];
      if (Array.isArray(urls)) {
        advancedEditUrls[key] = urls.map((url: string) =>
          transformUrlForOEM(url, oemConfig),
        );
      } else {
        advancedEditUrls[key] = transformUrlForOEM(urls, oemConfig);
      }
    });
    transformedAsset.advancedEditUrls = advancedEditUrls;
  }

  // 转换npm对象中的URL（如果有）
  if (transformedAsset.npm && typeof transformedAsset.npm === 'object') {
    // npm对象通常不包含URL，但为了完整性也检查一下
    Object.keys(transformedAsset.npm).forEach((key) => {
      if (
        typeof transformedAsset.npm[key] === 'string' &&
        (transformedAsset.npm[key].includes('cdn.appthen.com') ||
          transformedAsset.npm[key].includes('cdn.appthen.cn'))
      ) {
        transformedAsset.npm[key] = transformUrlForOEM(
          transformedAsset.npm[key],
          oemConfig,
        );
      }
    });
  }

  return transformedAsset;
};

/**
 * 转换资产JSON以适配OEM配置
 * @param assets 资产JSON
 * @param oemConfig OEM配置
 * @returns 转换后的资产JSON
 */
const transformAssetsForOEM = (
  assets: IPublicTypeAssetsJson,
  oemConfig: any,
): IPublicTypeAssetsJson => {
  if (!assets || !oemConfig) return assets;

  const transformedAssets: any = { ...assets };

  // 转换packages数组
  if (transformedAssets.packages && Array.isArray(transformedAssets.packages)) {
    transformedAssets.packages = transformedAssets.packages.map((pkg) =>
      transformAssetForOEM(pkg, oemConfig),
    );
  }

  // 转换components数组
  if (
    transformedAssets.components &&
    Array.isArray(transformedAssets.components)
  ) {
    transformedAssets.components = transformedAssets.components.map((comp) =>
      transformAssetForOEM(comp, oemConfig),
    );
  }

  // 转换utils数组 @TODO: utils 可能不存在
  if (transformedAssets.utils && Array.isArray(transformedAssets.utils)) {
    transformedAssets.utils = transformedAssets.utils.map((util) =>
      transformAssetForOEM(util, oemConfig),
    );
  }

  return transformedAssets;
};

export const getProjectAssetsJson = (
  project: LcProject,
  frame: DocFrameType,
) => {
  let __assets = getDefaultAssets(project, frame);
  if (project?.assets) {
    __assets = loadProjectAssets(
      __assets,
      JSON.parse(JSON.stringify(project?.assets)),
      frame,
    );
  }

  // 应用OEM配置转换
  const oemConfig = getOEMConfig();
  __assets = transformAssetsForOEM(__assets, oemConfig);
  return __assets;
};

/**
 * 加载项目依赖
 * @TODO: 需要根据项目框架类型，加载不同的依赖
 * @param sourceAssets 依赖源
 * @param project 项目
 */
export const loadProjectAssets = (
  sourceAssets: IPublicTypeAssetsJson,
  assets: LcProject['assets'],
  frame?: DocFrameType,
) => {
  // debug('loadProjectAssets: ', {
  //   sourceAssets,
  //   assets,
  //   frame,
  // });
  const __assets = sourceAssets;
  const extendsAssets = filterAssets(assets, frame);
  const extendsPackageNames = extendsAssets?.map((_) => _.package.package);
  // 删除已存在所有的同名包
  __assets.packages = __assets.packages?.filter(
    (p) => !extendsPackageNames.includes(p.package),
  );

  // console.log('__assets start: ', JSON.parse(JSON.stringify(__assets)));
  extendsAssets?.forEach((asset) => {
    const component = {
      exportName: asset.metaFile?.exportName,
      npm: {
        package: asset.package.package,
        version: asset.package.version,
      },
      url: asset.metaFile?.url,
    } as IPublicTypeRemoteComponentDescription;
    let hasReplaced = false;
    if (asset.advanced?.replacePackage) {
      const replacePackages = asset.advanced?.replacePackage?.split(',');
      // 替换依赖
      // console.log('替换依赖 start: ', asset.package.package, JSON.parse(JSON.stringify(__assets)));
      // TODO: 下方的替换方式会导致插入多个相同依赖，后续需要优化
      __assets.packages = __assets.packages.map((p) => {
        if (replacePackages.includes(p.package)) {
          hasReplaced = true;
          // 由于目前依赖配置中并不可以配置editUrls，导致目前存在旧数据，遂先删除
          delete asset.package.editUrls;
          return asset.package;
        }
        return p;
      });
      // console.log('替换依赖: ', asset.package.package, JSON.parse(JSON.stringify(__assets)));
      if (component.exportName) {
        __assets.components = __assets.components.map((c) => {
          if (replacePackages.includes(c.npm?.package)) {
            return component;
          }
          return c;
        });
      }
    }
    if (!hasReplaced) {
      __assets.packages.push(asset.package);
      if (
        asset.metaFile &&
        __assets.components.findIndex(
          (_) => _.exportName === component.exportName,
        ) === -1
      ) {
        __assets.components.push(component);
      }
    }
    if (asset.utils?.length > 0) {
      // @ts-ignore
      __assets.utils = (__assets.utils || []).concat(asset.utils).map((_) => {
        // 默认
        if (typeof _.npm.destructuring !== 'boolean') {
          _.npm.destructuring = true;
        }
        return _;
      });
    }
  });
  return __assets;
};
